home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 02 Useful Techniques / 08 Zarozinski / src / ffllapi / MemberFuncTrap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-16  |  10.0 KB  |  443 lines

  1. //
  2. // File:    MemberFuncTrap.cpp
  3. //
  4. // Purpose:    Implementation of the Trapezoid membership function
  5. //
  6. // Copyright ⌐ 1999-2001 Louder Than A Bomb! Software
  7. //
  8. // This file is part of the FFLL (Free Fuzzy Logic Library) project (http://ffll.sourceforge.net)
  9. // It is released under the BSD license, see http://ffll.sourceforge.net/license.txt for the full text.
  10. //
  11.  
  12. #include "MemberFuncTrap.h"
  13. #include "MemberFuncSingle.h"
  14. #include "FuzzyModelBase.h"
  15. #include "FuzzyVariableBase.h"
  16.  
  17. #ifdef _DEBUG  
  18. #undef THIS_FILE
  19. static char THIS_FILE[]=__FILE__; 
  20. #endif
  21.  
  22. //
  23. // Function:    MemberFuncTrap()
  24. // 
  25. // Purpose:        Constructor
  26. //
  27. // Arguments:
  28. //
  29. //        FuzzySetBase* _parent - Set this member function is part of
  30. //
  31. // Returns:
  32. //
  33. //        nothing
  34. //
  35. // Author:    Michael Zarozinski
  36. // Date:    8/99
  37. // 
  38. // Modification History
  39. // Author    Date        Modification
  40. // ------    ----        ------------
  41. //
  42. // 
  43. MemberFuncTrap::MemberFuncTrap(FuzzySetBase* _parent) : MemberFuncBase(_parent), FFLLBase(_parent)
  44. {
  45.     // create the nodes array
  46.     alloc_nodes( get_node_count() );
  47.  
  48. } // MemberFuncTrap::MemberFuncTrap()
  49.  
  50.  
  51. //
  52. // Function:    ~MemberFuncTrap()
  53. // 
  54. // Purpose:        Destructor
  55. //
  56. // Arguments:
  57. //
  58. //        none
  59. //
  60. // Returns:
  61. //
  62. //        nothing
  63. //
  64. // Author:    Michael Zarozinski
  65. // Date:    8/99
  66. // 
  67. // Modification History
  68. // Author    Date        Modification
  69. // ------    ----        ------------
  70. //
  71. // 
  72.  
  73. MemberFuncTrap::~MemberFuncTrap() 
  74. {
  75.     // nothing to do, base class(es) handle everything
  76. }
  77.  
  78.  
  79. //
  80. // Function: set_node()
  81. // 
  82. // Purpose:    This function moves a point to a new position. It performs
  83. //            checks to make sure the nodes are at valid positions (such as
  84. //            not allowing the last point to be BEFORE the mid point.
  85. // 
  86. // Arguments:
  87. //
  88. //        int            idx            -    index of the point to move
  89. //        int            x            -    x position to move to (in variable coords)
  90. //        int            y            -    x position to move to (in variable coords)
  91. //        bool        validate    -    indicates if we should perorm sanity checks (default is true)
  92. //
  93. // Returns:
  94. //
  95. //        void
  96. // 
  97. // Globals:
  98. //
  99. // Author:    Michael Zarozinski    
  100. // Date:    6/21/99
  101. // 
  102. //    Modification History
  103. //    Author        Date        Modification
  104. //    ------        ----        ------------
  105. //     
  106. //
  107. void MemberFuncTrap::set_node(int idx, int x, int y, bool validate /* = true */)
  108. {
  109.     if (!validate)
  110.         {
  111.         nodes[idx].y = y;
  112.         nodes[idx].x = x;
  113.         return;
  114.         }
  115.  
  116.       // set the 'y' value based on the shape of this curve - we don't
  117.     // allow them to change the 'y' for the triangle shape
  118.  
  119.     if (idx == 0 || idx == 3)
  120.         nodes[idx].y = 0;
  121.     else
  122.         nodes[idx].y = FuzzyVariableBase::get_dom_array_max_idx();
  123.  
  124.     // perform some sanity checks on the 'x' position
  125.  
  126.     if (idx == 1 || idx == 2)
  127.         { 
  128.         // we're dealing with the plateau
  129.         // make sure we don't overlap    
  130.         if (idx == 1)
  131.             {
  132.             if (x >= nodes[2].x)
  133.                 nodes[1].x  = nodes[2].x;
  134.             else if ( x < get_start_x())
  135.                 nodes[idx].x = get_start_x();
  136.             else if ( x > get_end_x())
  137.                 nodes[idx].x = get_end_x();
  138.             else
  139.                 nodes[idx].x = x;
  140.  
  141.             } // end if left plateau point
  142.         else if (idx == 2)
  143.             {
  144.             if (x <= nodes[1].x)
  145.                 nodes[2].x  = nodes[1].x;
  146.             else if ( x < get_start_x())
  147.                 nodes[idx].x = get_start_x();
  148.             else if ( x > get_end_x())
  149.                 nodes[idx].x = get_end_x();
  150.             else 
  151.                 nodes[idx].x = x;
  152.      
  153.             } // end if right plateau point
  154.         } 
  155.     else
  156.         {
  157.         // idx is 0 or 3 (start/end nodes)
  158.  
  159.         // check the first point...
  160.         if (idx == 0)
  161.             {
  162.             // we're dealing with an end point
  163.             if ( x > nodes[1].x)
  164.                 nodes[idx].x = nodes[1].x;
  165.             else
  166.                 nodes[idx].x =  x; // overloaded operator=() performs some additional validation for us
  167.             }
  168.         else
  169.             { 
  170.             // we're dealing with the last point
  171.             if ( x < nodes[2].x)
  172.                 nodes[idx].x = nodes[2].x;
  173.             else
  174.                 nodes[idx].x =  x; // overloaded operator=() performs some additional validation for us
  175.             }
  176.  
  177.         } // end if dealing with start or end point
  178.  
  179.  
  180. } // end MemberFuncTrap::set_anchor()
  181.  
  182.  
  183. //
  184. // Function:    init_nodes()
  185. // 
  186. // Purpose:        Initialized all the nodes to reasonable values depending on the 
  187. //                mid-point and width passed in.
  188. //
  189. // Arguments:
  190. //
  191. //            int        mid_pt_x    -    mid point of the member func
  192. //            int        width        -    how wide this set is
  193. // 
  194. // Returns:
  195. //
  196. //            none
  197. //
  198. // Author:    Michael Zarozinski
  199. // Date:    6/21/99
  200. // 
  201. // Modification History
  202. // Author    Date        Modification
  203. // ------    ----        ------------
  204. //
  205. //
  206.  
  207. void MemberFuncTrap::init_nodes(int mid_pt_x, int term_width)
  208. {
  209.     int node_count = get_node_count();
  210.  
  211.     // if start x is too close to the end move it...
  212.  
  213.     if (mid_pt_x + term_width/2 >  FuzzyVariableBase::get_x_array_count())
  214.         mid_pt_x = FuzzyVariableBase::get_x_array_max_idx() - term_width/2;
  215.  
  216.      nodes[0].x = mid_pt_x - term_width/2;
  217.     nodes[0].y = 0;
  218.  
  219.     nodes[1].x = nodes[0].x + term_width/(node_count - 1);
  220.     nodes[1].y = FuzzyVariableBase::get_dom_array_max_idx();
  221.  
  222.     nodes[2].x = nodes[1].x + term_width/(node_count - 1);
  223.     nodes[2].y = FuzzyVariableBase::get_dom_array_max_idx();
  224.  
  225.     nodes[3].x = nodes[0].x + term_width ;
  226.     nodes[3].y = 0;
  227.  
  228.     calc(); // re-calc values array
  229.  
  230. } // end MemberFuncTrap::set_all_anchors()
  231.  
  232.  
  233. //
  234. // Function:    set_ramp()
  235. // 
  236. // Purpose:        Virtual function that sets the nodes appropriately
  237. //                depending on the type of ramp (or no ramp) that we want.
  238. //
  239. // Arguments:
  240. //
  241. //        int left_right_ind        -    indicates if we're making a left (1) or right (0) ramp
  242. //        int hi_lo_ind            -    indicates if we're creating (1) or removing (0) ramp
  243. //
  244. // Returns:
  245. //
  246. //        void
  247. //
  248. // Author:    Michael Zarozinski
  249. // Date:    9/99
  250. // 
  251. // Modification History
  252. // Author    Date        Modification
  253. // ------    ----        ------------
  254. //
  255. //
  256. void  MemberFuncTrap::set_ramp(int hi_lo_ind, int left_right_ind)
  257. {
  258.  
  259.     // initialize the nodes so we have a good starting point
  260.     init_nodes(nodes[0].x + (nodes[3].x - nodes[0].x)/2, nodes[3].x - nodes[0].x);
  261.  
  262.     // figure out which side we're changing
  263.     if (left_right_ind)
  264.         {
  265.         if (hi_lo_ind == 1)
  266.             {
  267.             // create a ramp
  268.             nodes[1].x = nodes[0].x = 0;
  269.             }
  270.         else
  271.             {
  272.              // removing a ramp - set the 1st point in the plateau 
  273.             // midway between the 1st anchor and the 2nd point in the plateau
  274.             nodes[1].x = nodes[0].x + (nodes[2].x - nodes[0].x)/2; 
  275.             }
  276.         }
  277.     else
  278.         {
  279.         // right ramp
  280.         if (hi_lo_ind == 1)
  281.             {
  282.             // making a high ramp
  283.             nodes[2].x = nodes[3].x = FuzzyVariableBase::get_x_array_max_idx();
  284.             }
  285.         else
  286.             {
  287.              // removing a ramp - set the 2nd point in the plateau 
  288.             // midway between the 2nd point in the plateau and the last anchor
  289.             nodes[2].x = nodes[1].x + (nodes[3].x - nodes[1].x)/2; 
  290.             }
  291.         } // end if dealing with 2nd half of function
  292.  
  293.         // call the ancestor to deal with common code...
  294.     MemberFuncBase::set_ramp(hi_lo_ind, left_right_ind);
  295.  
  296. } // end MemberFuncTrap::set_ramp()
  297.  
  298.  
  299. //
  300. // Function:    calc()
  301. // 
  302. // Purpose:        Virtual function that calculates the 'y' points for this curve
  303. //                 and fills in the values[] array.
  304. //
  305. // Arguments:
  306. //
  307. //        none
  308. //
  309. // Returns:
  310. //
  311. //        void
  312. //
  313. // Author:    Michael Zarozinski
  314. // Date:    5/99
  315. // 
  316. // Modification History
  317. // Author    Date        Modification
  318. // ------    ----        ------------
  319. //
  320.  
  321. void MemberFuncTrap::calc()
  322. {
  323.     int        i;    // counter
  324.     double    m;    // slope of the curve, this is the 'm' in y = mx + b
  325.      double    b;    // b for y = mx + b
  326.  
  327.     // clear out the whole values[] array
  328.     clear_values();
  329.  
  330.     m = 1.0; // init slope
  331.  
  332.     double divisor = nodes[1].x - nodes[0].x;
  333.  
  334.     // make sure we don't div by 0...  
  335.     if (divisor)
  336.         m /= divisor; // this is 1/divisor cuz the 'y' max is 1.0
  337.  
  338.     // fill in the first part of the curve
  339.     for (i = nodes[0].x; i <= nodes[1].x; i++)
  340.         {
  341.         // we "shift" things by subtracting nodes[0].x so the calc of the y = mx + b
  342.         set_value(i, m * (i - nodes[0].x) ); // y = mx + b (b is zero in this case)
  343.         }
  344.  
  345.     // fill in the plateau part
  346.     for (i = nodes[1].x; i <= nodes[2].x; i++)
  347.         set_value(i, 1.0f);
  348.  
  349.     // calc the slope for the 3rd part of the line...
  350.     divisor = nodes[3].x - nodes[2].x;
  351.  
  352.     m = -1.0;    // slope is negative for this part of the curve
  353.  
  354.     if (divisor)
  355.          m /=  divisor;
  356.        
  357.     b = 1.0;    // be is the max 'y' value
  358.  
  359.     // fill in the 3rd part of theline
  360.  
  361.      for (i = nodes[2].x; i <= nodes[3].x; i++)
  362.         {
  363.         // we "shift" things by subtracting nodes[2].x so the calc of the y = mx + b
  364.         set_value(i, (m * (i - nodes[2].x)) + b );  
  365.         }
  366.  
  367. } // end MemberFuncTrap::calc()
  368.  
  369. //
  370. // Function:    expand()
  371. // 
  372. // Purpose:        Uniformly expands this member func around it's center
  373. //
  374. // Arguments:
  375. //
  376. //        int x_delta - how much to expand the member func by        
  377. //
  378. // Returns:
  379. //
  380. //        void
  381. //
  382. // Author:    Michael Zarozinski
  383. // Date:    9/99
  384. // 
  385. // Modification History
  386. // Author    Date        Modification
  387. // ------    ----        ------------
  388. //
  389. //
  390. void MemberFuncTrap::expand(int x_delta )
  391. {
  392.     // call init-nodes rather than move nodes to make it look better...
  393.     init_nodes((nodes[2].x - nodes[1].x)/2, (nodes[3].x - nodes[0].x) + abs(x_delta));
  394.      
  395. } // end MemberFuncTrap::expand()
  396.  
  397. //
  398. // Function:    shrink()
  399. // 
  400. // Purpose:        Uniformly shrinks this member func around it's center
  401. //
  402. // Arguments:
  403. //
  404. //        int x_delta - how much to shrink the member func by        
  405. //
  406. // Returns:
  407. //
  408. //        void
  409. //
  410. // Author:    Michael Zarozinski
  411. // Date:    9/99
  412. // 
  413. // Modification History
  414. // Author    Date        Modification
  415. // ------    ----        ------------
  416. //
  417. // 
  418. void MemberFuncTrap::shrink(int x_delta )
  419. {
  420.      // call init-nodes rather than move nodes to make it look better...
  421.     init_nodes((nodes[2].x - nodes[1].x)/2, (nodes[3].x - nodes[0].x) - abs(x_delta));
  422.      
  423. } // end MemberFuncTrap::shrink()
  424.  
  425. /////////////////////////////////////////////////////////////////////
  426. ////////// Trivial Functions That Don't Require Headers /////////////
  427. /////////////////////////////////////////////////////////////////////
  428.   
  429. int MemberFuncTrap::get_center_x(void) const 
  430. {
  431.     // the "mid" x is sepecific to the shape... the start/end x funcs
  432.     // are in the ancestor    
  433.     return nodes[1].x + ((nodes[2].x - nodes[1].x)/2);
  434. };
  435. int MemberFuncTrap::get_func_type()  const 
  436. {
  437.     return MemberFuncBase::TRAPEZOID;
  438. };
  439. int MemberFuncTrap::get_node_count() const 
  440.     return 4;
  441. };
  442.